package model;

import interfaces.TagDataSetter;

import java.util.Date;
import java.util.Random;

import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.TwitterException;

/**
 * @author Manseer Marcel  
 * @author Plavsic Maja
 * @author Pretsch Paul
 */
public class TagDataCrawler implements Runnable {
	
	private final Model model;
	private final String hashtag;
	private final Date date;

	public TagDataCrawler(Model model, String hashtag, Date date)
	{
		this.model = model;
		this.hashtag = hashtag;
		this.date = Tools.TruncateTime(date);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		
		final TagDataSetter tagData = this.model.getBuffer().getNewDataSetter(hashtag, date);
		
		if (tagData != null) {
			// loop until no rate limitation occures
			boolean retry = true;
			while (retry) {
				retry = false;
				
				System.out.println(String.format("Crawler: running Crawler for %s on %s", tagData.getTag(), Tools.FormattedTwitterDate(date)));
				
				Integer count = 0;
	            try {
	                Query query = new Query(tagData.getTag());
	                query.setCount(100);
	                query.setSince(Tools.FormattedTwitterDate(date));
	                query.setUntil(Tools.FormattedTwitterDate(Tools.IncDay(date, 1)));
	                
	                QueryResult result;
	                do {
	                		result = this.model.getTwitter().search(query);
	                		count += result.getTweets().size();
	                		tagData.setCount(count);
	                } while ((query = result.nextQuery()) != null);
	
	                tagData.setCount(count);
	                tagData.setFinished();
				} catch (TwitterException te) {
					System.out.println("Crawler: failed to fetch tweets: " + te.getMessage());
					if (te.getStatusCode() == 429) {
						try {
							Random r = new Random();
							// sleep max 1 min (+-30s): limit is 15requests/15min -> 1request/1min
							int sleep = Math.min(30 + r.nextInt(60), te.getRateLimitStatus().getSecondsUntilReset());
							System.out.println(String.format("Crawler: sleep for %ds/%ds", sleep, te.getRateLimitStatus().getSecondsUntilReset()));
							Thread.sleep(sleep * 1000);
							retry = true;
						} catch (InterruptedException e) {
							tagData.setExceptionOccured(e.getMessage());
							tagData.delete();
						}
					} else {
						tagData.setExceptionOccured(te.getMessage());
						tagData.delete();
					}
				} finally {
	                System.out.println(String.format("Crawler: count for %s on %s = %d", tagData.getTag(), Tools.FormattedTwitterDate(date), count));
				}			
			}
		}
	}

}
